home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2000 March / maximum-cd-2000-03.iso / Quake3 Game Source / Q3AGameSource.exe / Main / ui_playermodel.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-18  |  19.8 KB  |  709 lines

  1. // Copyright (C) 1999-2000 Id Software, Inc.
  2. //
  3. #include "ui_local.h"
  4.  
  5. #define MODEL_BACK0            "menu/art/back_0"
  6. #define MODEL_BACK1            "menu/art/back_1"
  7. #define MODEL_SELECT        "menu/art/opponents_select"
  8. #define MODEL_SELECTED        "menu/art/opponents_selected"
  9. #define MODEL_FRAMEL        "menu/art/frame1_l"
  10. #define MODEL_FRAMER        "menu/art/frame1_r"
  11. #define MODEL_PORTS            "menu/art/player_models_ports"
  12. #define MODEL_ARROWS        "menu/art/gs_arrows_0"
  13. #define MODEL_ARROWSL        "menu/art/gs_arrows_l"
  14. #define MODEL_ARROWSR        "menu/art/gs_arrows_r"
  15.  
  16. #define LOW_MEMORY            (5 * 1024 * 1024)
  17.  
  18. static char* playermodel_artlist[] =
  19. {
  20.     MODEL_BACK0,    
  21.     MODEL_BACK1,    
  22.     MODEL_SELECT,
  23.     MODEL_SELECTED,
  24.     MODEL_FRAMEL,
  25.     MODEL_FRAMER,
  26.     MODEL_PORTS,    
  27.     MODEL_ARROWS,
  28.     MODEL_ARROWSL,
  29.     MODEL_ARROWSR,
  30.     NULL
  31. };
  32.  
  33. #define PLAYERGRID_COLS        4
  34. #define PLAYERGRID_ROWS        4
  35. #define MAX_MODELSPERPAGE    (PLAYERGRID_ROWS*PLAYERGRID_COLS)
  36.  
  37. #define MAX_PLAYERMODELS    256
  38.  
  39. #define ID_PLAYERPIC0        0
  40. #define ID_PLAYERPIC1        1
  41. #define ID_PLAYERPIC2        2
  42. #define ID_PLAYERPIC3        3
  43. #define ID_PLAYERPIC4        4
  44. #define ID_PLAYERPIC5        5
  45. #define ID_PLAYERPIC6        6
  46. #define ID_PLAYERPIC7        7
  47. #define ID_PLAYERPIC8        8
  48. #define ID_PLAYERPIC9        9
  49. #define ID_PLAYERPIC10        10
  50. #define ID_PLAYERPIC11        11
  51. #define ID_PLAYERPIC12        12
  52. #define ID_PLAYERPIC13        13
  53. #define ID_PLAYERPIC14        14
  54. #define ID_PLAYERPIC15        15
  55. #define ID_PREVPAGE            100
  56. #define ID_NEXTPAGE            101
  57. #define ID_BACK                102
  58.  
  59. typedef struct
  60. {
  61.     menuframework_s    menu;
  62.     menubitmap_s    pics[MAX_MODELSPERPAGE];
  63.     menubitmap_s    picbuttons[MAX_MODELSPERPAGE];
  64.     menubitmap_s    framel;
  65.     menubitmap_s    framer;
  66.     menubitmap_s    ports;
  67.     menutext_s        banner;
  68.     menubitmap_s    back;
  69.     menubitmap_s    player;
  70.     menubitmap_s    arrows;
  71.     menubitmap_s    left;
  72.     menubitmap_s    right;
  73.     menutext_s        modelname;
  74.     menutext_s        skinname;
  75.     menutext_s        playername;
  76.     playerInfo_t    playerinfo;
  77.     int                nummodels;
  78.     char            modelnames[MAX_PLAYERMODELS][128];
  79.     int                modelpage;
  80.     int                numpages;
  81.     char            modelskin[64];
  82.     int                selectedmodel;
  83. } playermodel_t;
  84.  
  85. static playermodel_t s_playermodel;
  86.  
  87. /*
  88. =================
  89. PlayerModel_UpdateGrid
  90. =================
  91. */
  92. static void PlayerModel_UpdateGrid( void )
  93. {
  94.     int    i;
  95.     int    j;
  96.  
  97.     j = s_playermodel.modelpage * MAX_MODELSPERPAGE;
  98.     for (i=0; i<PLAYERGRID_ROWS*PLAYERGRID_COLS; i++,j++)
  99.     {
  100.         if (j < s_playermodel.nummodels)
  101.         { 
  102.             // model/skin portrait
  103.              s_playermodel.pics[i].generic.name         = s_playermodel.modelnames[j];
  104.             s_playermodel.picbuttons[i].generic.flags &= ~QMF_INACTIVE;
  105.         }
  106.         else
  107.         {
  108.             // dead slot
  109.              s_playermodel.pics[i].generic.name         = NULL;
  110.             s_playermodel.picbuttons[i].generic.flags |= QMF_INACTIVE;
  111.         }
  112.  
  113.          s_playermodel.pics[i].generic.flags       &= ~QMF_HIGHLIGHT;
  114.          s_playermodel.pics[i].shader               = 0;
  115.          s_playermodel.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
  116.     }
  117.  
  118.     if (s_playermodel.selectedmodel/MAX_MODELSPERPAGE == s_playermodel.modelpage)
  119.     {
  120.         // set selected model
  121.         i = s_playermodel.selectedmodel % MAX_MODELSPERPAGE;
  122.  
  123.         s_playermodel.pics[i].generic.flags       |= QMF_HIGHLIGHT;
  124.         s_playermodel.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
  125.     }
  126.  
  127.     if (s_playermodel.numpages > 1)
  128.     {
  129.         if (s_playermodel.modelpage > 0)
  130.             s_playermodel.left.generic.flags &= ~QMF_INACTIVE;
  131.         else
  132.             s_playermodel.left.generic.flags |= QMF_INACTIVE;
  133.  
  134.         if (s_playermodel.modelpage < s_playermodel.numpages-1)
  135.             s_playermodel.right.generic.flags &= ~QMF_INACTIVE;
  136.         else
  137.             s_playermodel.right.generic.flags |= QMF_INACTIVE;
  138.     }
  139.     else
  140.     {
  141.         // hide left/right markers
  142.         s_playermodel.left.generic.flags |= QMF_INACTIVE;
  143.         s_playermodel.right.generic.flags |= QMF_INACTIVE;
  144.     }
  145. }
  146.  
  147. /*
  148. =================
  149. PlayerModel_UpdateModel
  150. =================
  151. */
  152. static void PlayerModel_UpdateModel( void )
  153. {
  154.     vec3_t    viewangles;
  155.     vec3_t    moveangles;
  156.  
  157.     memset( &s_playermodel.playerinfo, 0, sizeof(playerInfo_t) );
  158.     
  159.     viewangles[YAW]   = 180 - 30;
  160.     viewangles[PITCH] = 0;
  161.     viewangles[ROLL]  = 0;
  162.     VectorClear( moveangles );
  163.  
  164.     UI_PlayerInfo_SetModel( &s_playermodel.playerinfo, s_playermodel.modelskin );
  165.     UI_PlayerInfo_SetInfo( &s_playermodel.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, moveangles, WP_MACHINEGUN, qfalse );
  166. }
  167.  
  168. /*
  169. =================
  170. PlayerModel_SaveChanges
  171. =================
  172. */
  173. static void PlayerModel_SaveChanges( void )
  174. {
  175.     trap_Cvar_Set( "model", s_playermodel.modelskin );
  176. }
  177.  
  178. /*
  179. =================
  180. PlayerModel_MenuEvent
  181. =================
  182. */
  183. static void PlayerModel_MenuEvent( void* ptr, int event )
  184. {
  185.     if (event != QM_ACTIVATED)
  186.         return;
  187.  
  188.     switch (((menucommon_s*)ptr)->id)
  189.     {
  190.         case ID_PREVPAGE:
  191.             if (s_playermodel.modelpage > 0)
  192.             {
  193.                 s_playermodel.modelpage--;
  194.                 PlayerModel_UpdateGrid();
  195.             }
  196.             break;
  197.  
  198.         case ID_NEXTPAGE:
  199.             if (s_playermodel.modelpage < s_playermodel.numpages-1)
  200.             {
  201.                 s_playermodel.modelpage++;
  202.                 PlayerModel_UpdateGrid();
  203.             }
  204.             break;
  205.  
  206.         case ID_BACK:
  207.             PlayerModel_SaveChanges();
  208.             UI_PopMenu();
  209.             break;
  210.     }
  211. }
  212.  
  213. /*
  214. =================
  215. PlayerModel_MenuKey
  216. =================
  217. */
  218. static sfxHandle_t PlayerModel_MenuKey( int key )
  219. {
  220.     menucommon_s*    m;
  221.     int                picnum;
  222.  
  223.     switch (key)
  224.     {
  225.         case K_KP_LEFTARROW:
  226.         case K_LEFTARROW:
  227.             m = Menu_ItemAtCursor(&s_playermodel.menu);
  228.             picnum = m->id - ID_PLAYERPIC0;
  229.             if (picnum >= 0 && picnum <= 15)
  230.             {
  231.                 if (picnum > 0)
  232.                 {
  233.                     Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor-1);
  234.                     return (menu_move_sound);
  235.                     
  236.                 }
  237.                 else if (s_playermodel.modelpage > 0)
  238.                 {
  239.                     s_playermodel.modelpage--;
  240.                     Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor+15);
  241.                     PlayerModel_UpdateGrid();
  242.                     return (menu_move_sound);
  243.                 }
  244.                 else
  245.                     return (menu_buzz_sound);
  246.             }
  247.             break;
  248.  
  249.         case K_KP_RIGHTARROW:
  250.         case K_RIGHTARROW:
  251.             m = Menu_ItemAtCursor(&s_playermodel.menu);
  252.             picnum = m->id - ID_PLAYERPIC0;
  253.             if (picnum >= 0 && picnum <= 15)
  254.             {
  255.                 if ((picnum < 15) && (s_playermodel.modelpage*MAX_MODELSPERPAGE + picnum+1 < s_playermodel.nummodels))
  256.                 {
  257.                     Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor+1);
  258.                     return (menu_move_sound);
  259.                 }                    
  260.                 else if ((picnum == 15) && (s_playermodel.modelpage < s_playermodel.numpages-1))
  261.                 {
  262.                     s_playermodel.modelpage++;
  263.                     Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor-15);
  264.                     PlayerModel_UpdateGrid();
  265.                     return (menu_move_sound);
  266.                 }
  267.                 else
  268.                     return (menu_buzz_sound);
  269.             }
  270.             break;
  271.             
  272.         case K_MOUSE2:
  273.         case K_ESCAPE:
  274.             PlayerModel_SaveChanges();
  275.             break;
  276.     }
  277.  
  278.     return ( Menu_DefaultKey( &s_playermodel.menu, key ) );
  279. }
  280.  
  281. /*
  282. =================
  283. PlayerModel_PicEvent
  284. =================
  285. */
  286. static void PlayerModel_PicEvent( void* ptr, int event )
  287. {
  288.     int                modelnum;
  289.     int                maxlen;
  290.     char*            buffptr;
  291.     char*            pdest;
  292.     int                i;
  293.  
  294.     if (event != QM_ACTIVATED)
  295.         return;
  296.  
  297.     for (i=0; i<PLAYERGRID_ROWS*PLAYERGRID_COLS; i++)
  298.     {
  299.         // reset
  300.          s_playermodel.pics[i].generic.flags       &= ~QMF_HIGHLIGHT;
  301.          s_playermodel.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
  302.     }
  303.  
  304.     // set selected
  305.     i = ((menucommon_s*)ptr)->id - ID_PLAYERPIC0;
  306.     s_playermodel.pics[i].generic.flags       |= QMF_HIGHLIGHT;
  307.     s_playermodel.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
  308.  
  309.     // get model and strip icon_
  310.     modelnum = s_playermodel.modelpage*MAX_MODELSPERPAGE + i;
  311.     buffptr  = s_playermodel.modelnames[modelnum] + strlen("models/players/");
  312.     pdest    = strstr(buffptr,"icon_");
  313.     if (pdest)
  314.     {
  315.         // track the whole model/skin name
  316.         Q_strncpyz(s_playermodel.modelskin,buffptr,pdest-buffptr+1);
  317.         strcat(s_playermodel.modelskin,pdest + 5);
  318.  
  319.         // seperate the model name
  320.         maxlen = pdest-buffptr;
  321.         if (maxlen > 16)
  322.             maxlen = 16;
  323.         Q_strncpyz( s_playermodel.modelname.string, buffptr, maxlen );
  324.         Q_strupr( s_playermodel.modelname.string );
  325.  
  326.         // seperate the skin name
  327.         maxlen = strlen(pdest+5)+1;
  328.         if (maxlen > 16)
  329.             maxlen = 16;
  330.         Q_strncpyz( s_playermodel.skinname.string, pdest+5, maxlen );
  331.         Q_strupr( s_playermodel.skinname.string );
  332.  
  333.         s_playermodel.selectedmodel = modelnum;
  334.  
  335.         if( trap_MemoryRemaining() > LOW_MEMORY ) {
  336.             PlayerModel_UpdateModel();
  337.         }
  338.     }
  339. }
  340.  
  341. /*
  342. =================
  343. PlayerModel_DrawPlayer
  344. =================
  345. */
  346. static void PlayerModel_DrawPlayer( void *self )
  347. {
  348.     menubitmap_s*    b;
  349.  
  350.     b = (menubitmap_s*) self;
  351.  
  352.     if( trap_MemoryRemaining() <= LOW_MEMORY ) {
  353.         UI_DrawProportionalString( b->generic.x, b->generic.y + b->height / 2, "LOW MEMORY", UI_LEFT, color_red );
  354.         return;
  355.     }
  356.  
  357.     UI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_playermodel.playerinfo, uis.realtime/2 );
  358. }
  359.  
  360. /*
  361. =================
  362. PlayerModel_BuildList
  363. =================
  364. */
  365. static void PlayerModel_BuildList( void )
  366. {
  367.     int        numdirs;
  368.     int        numfiles;
  369.     char    dirlist[1024];
  370.     char    filelist[1024];
  371.     char    skinname[64];
  372.     char*    dirptr;
  373.     char*    fileptr;
  374.     int        i;
  375.     int        j;
  376.     int        dirlen;
  377.     int        filelen;
  378.     qboolean precache;
  379.  
  380.     precache = trap_Cvar_VariableValue("com_buildscript");
  381.  
  382.     s_playermodel.modelpage = 0;
  383.     s_playermodel.nummodels = 0;
  384.  
  385.     // iterate directory of all player models
  386.     numdirs = trap_FS_GetFileList("models/players", "/", dirlist, 1024 );
  387.     dirptr  = dirlist;
  388.     for (i=0; i<numdirs; i++,dirptr+=dirlen+1)
  389.     {
  390.         dirlen = strlen(dirptr);
  391.         
  392.         if (dirlen && dirptr[dirlen-1]=='/') dirptr[dirlen-1]='\0';
  393.  
  394.         if (!strcmp(dirptr,".") || !strcmp(dirptr,".."))
  395.             continue;
  396.             
  397.         // iterate all skin files in directory
  398.         numfiles = trap_FS_GetFileList( va("models/players/%s",dirptr), "tga", filelist, 1024 );
  399.         fileptr  = filelist;
  400.         for (j=0; j<numfiles;j++,fileptr+=filelen+1)
  401.         {
  402.             filelen = strlen(fileptr);
  403.  
  404.             COM_StripExtension(fileptr,skinname);
  405.  
  406.             // look for icon_????
  407.             if (!Q_stricmpn(skinname,"icon_",5))
  408.             {
  409.                 Com_sprintf( s_playermodel.modelnames[s_playermodel.nummodels++],
  410.                     sizeof( s_playermodel.modelnames[s_playermodel.nummodels] ),
  411.                     "models/players/%s/%s", dirptr, skinname );
  412.                 if (s_playermodel.nummodels >= MAX_PLAYERMODELS)
  413.                     return;
  414.             }
  415.  
  416.             if( precache ) {
  417.                 trap_S_RegisterSound( va( "sound/player/announce/%s_wins.wav", skinname ) );
  418.             }
  419.         }
  420.     }    
  421.  
  422.     //APSFIXME - Degenerate no models case
  423.  
  424.     s_playermodel.numpages = s_playermodel.nummodels/MAX_MODELSPERPAGE;
  425.     if (s_playermodel.nummodels % MAX_MODELSPERPAGE)
  426.         s_playermodel.numpages++;
  427. }
  428.  
  429. /*
  430. =================
  431. PlayerModel_SetMenuItems
  432. =================
  433. */
  434. static void PlayerModel_SetMenuItems( void )
  435. {
  436.     int                i;
  437.     int                maxlen;
  438.     char            modelskin[64];
  439.     char*            buffptr;
  440.     char*            pdest;
  441.  
  442.     // name
  443.     trap_Cvar_VariableStringBuffer( "name", s_playermodel.playername.string, 16 );
  444.     Q_CleanStr( s_playermodel.playername.string );
  445.  
  446.     // model
  447.     trap_Cvar_VariableStringBuffer( "model", s_playermodel.modelskin, 64 );
  448.     
  449.     // find model in our list
  450.     for (i=0; i<s_playermodel.nummodels; i++)
  451.     {
  452.         // strip icon_
  453.         buffptr  = s_playermodel.modelnames[i] + strlen("models/players/");
  454.         pdest    = strstr(buffptr,"icon_");
  455.         if (pdest)
  456.         {
  457.             Q_strncpyz(modelskin,buffptr,pdest-buffptr+1);
  458.             strcat(modelskin,pdest + 5);
  459.         }
  460.         else
  461.             continue;
  462.  
  463.         if (!Q_stricmp( s_playermodel.modelskin, modelskin ))
  464.         {
  465.             // found pic, set selection here        
  466.             s_playermodel.selectedmodel = i;
  467.             s_playermodel.modelpage     = i/MAX_MODELSPERPAGE;
  468.  
  469.             // seperate the model name
  470.             maxlen = pdest-buffptr;
  471.             if (maxlen > 16)
  472.                 maxlen = 16;
  473.             Q_strncpyz( s_playermodel.modelname.string, buffptr, maxlen );
  474.             Q_strupr( s_playermodel.modelname.string );
  475.  
  476.             // seperate the skin name
  477.             maxlen = strlen(pdest+5)+1;
  478.             if (maxlen > 16)
  479.                 maxlen = 16;
  480.             Q_strncpyz( s_playermodel.skinname.string, pdest+5, maxlen );
  481.             Q_strupr( s_playermodel.skinname.string );
  482.             break;
  483.         }
  484.     }
  485. }
  486.  
  487. /*
  488. =================
  489. PlayerModel_MenuInit
  490. =================
  491. */
  492. static void PlayerModel_MenuInit( void )
  493. {
  494.     int            i;
  495.     int            j;
  496.     int            k;
  497.     int            x;
  498.     int            y;
  499.     static char    playername[32];
  500.     static char    modelname[32];
  501.     static char    skinname[32];
  502.  
  503.     // zero set all our globals
  504.     memset( &s_playermodel, 0 ,sizeof(playermodel_t) );
  505.  
  506.     PlayerModel_Cache();
  507.  
  508.     s_playermodel.menu.key        = PlayerModel_MenuKey;
  509.     s_playermodel.menu.wrapAround = qtrue;
  510.     s_playermodel.menu.fullscreen = qtrue;
  511.  
  512.     s_playermodel.banner.generic.type  = MTYPE_BTEXT;
  513.     s_playermodel.banner.generic.x     = 320;
  514.     s_playermodel.banner.generic.y     = 16;
  515.     s_playermodel.banner.string        = "PLAYER MODEL";
  516.     s_playermodel.banner.color         = color_white;
  517.     s_playermodel.banner.style         = UI_CENTER;
  518.  
  519.     s_playermodel.framel.generic.type  = MTYPE_BITMAP;
  520.     s_playermodel.framel.generic.name  = MODEL_FRAMEL;
  521.     s_playermodel.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
  522.     s_playermodel.framel.generic.x     = 0;
  523.     s_playermodel.framel.generic.y     = 78;
  524.     s_playermodel.framel.width         = 256;
  525.     s_playermodel.framel.height        = 329;
  526.  
  527.     s_playermodel.framer.generic.type  = MTYPE_BITMAP;
  528.     s_playermodel.framer.generic.name  = MODEL_FRAMER;
  529.     s_playermodel.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
  530.     s_playermodel.framer.generic.x     = 376;
  531.     s_playermodel.framer.generic.y     = 76;
  532.     s_playermodel.framer.width         = 256;
  533.     s_playermodel.framer.height        = 334;
  534.  
  535.     s_playermodel.ports.generic.type  = MTYPE_BITMAP;
  536.     s_playermodel.ports.generic.name  = MODEL_PORTS;
  537.     s_playermodel.ports.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
  538.     s_playermodel.ports.generic.x     = 50;
  539.     s_playermodel.ports.generic.y     = 59;
  540.     s_playermodel.ports.width         = 274;
  541.     s_playermodel.ports.height        = 274;
  542.  
  543.     y =    59;
  544.     for (i=0,k=0; i<PLAYERGRID_ROWS; i++)
  545.     {
  546.         x =    50;
  547.         for (j=0; j<PLAYERGRID_COLS; j++,k++)
  548.         {
  549.             s_playermodel.pics[k].generic.type       = MTYPE_BITMAP;
  550.             s_playermodel.pics[k].generic.flags    = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
  551.             s_playermodel.pics[k].generic.x           = x;
  552.             s_playermodel.pics[k].generic.y           = y;
  553.             s_playermodel.pics[k].width             = 64;
  554.             s_playermodel.pics[k].height             = 64;
  555.             s_playermodel.pics[k].focuspic         = MODEL_SELECTED;
  556.             s_playermodel.pics[k].focuscolor       = colorRed;
  557.  
  558.             s_playermodel.picbuttons[k].generic.type     = MTYPE_BITMAP;
  559.             s_playermodel.picbuttons[k].generic.flags    = QMF_LEFT_JUSTIFY|QMF_NODEFAULTINIT|QMF_PULSEIFFOCUS;
  560.             s_playermodel.picbuttons[k].generic.id         = ID_PLAYERPIC0+k;
  561.             s_playermodel.picbuttons[k].generic.callback = PlayerModel_PicEvent;
  562.             s_playermodel.picbuttons[k].generic.x         = x - 16;
  563.             s_playermodel.picbuttons[k].generic.y         = y - 16;
  564.             s_playermodel.picbuttons[k].generic.left     = x;
  565.             s_playermodel.picbuttons[k].generic.top         = y;
  566.             s_playermodel.picbuttons[k].generic.right     = x + 64;
  567.             s_playermodel.picbuttons[k].generic.bottom   = y + 64;
  568.             s_playermodel.picbuttons[k].width               = 128;
  569.             s_playermodel.picbuttons[k].height           = 128;
  570.             s_playermodel.picbuttons[k].focuspic           = MODEL_SELECT;
  571.             s_playermodel.picbuttons[k].focuscolor       = colorRed;
  572.  
  573.             x += 64+6;
  574.         }
  575.         y += 64+6;
  576.     }
  577.  
  578.     s_playermodel.playername.generic.type  = MTYPE_PTEXT;
  579.     s_playermodel.playername.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
  580.     s_playermodel.playername.generic.x       = 320;
  581.     s_playermodel.playername.generic.y       = 440;
  582.     s_playermodel.playername.string           = playername;
  583.     s_playermodel.playername.style           = UI_CENTER;
  584.     s_playermodel.playername.color         = text_color_normal;
  585.  
  586.     s_playermodel.modelname.generic.type  = MTYPE_PTEXT;
  587.     s_playermodel.modelname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
  588.     s_playermodel.modelname.generic.x      = 497;
  589.     s_playermodel.modelname.generic.y      = 54;
  590.     s_playermodel.modelname.string          = modelname;
  591.     s_playermodel.modelname.style          = UI_CENTER;
  592.     s_playermodel.modelname.color         = text_color_normal;
  593.  
  594.     s_playermodel.skinname.generic.type   = MTYPE_PTEXT;
  595.     s_playermodel.skinname.generic.flags  = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
  596.     s_playermodel.skinname.generic.x      = 497;
  597.     s_playermodel.skinname.generic.y      = 394;
  598.     s_playermodel.skinname.string          = skinname;
  599.     s_playermodel.skinname.style          = UI_CENTER;
  600.     s_playermodel.skinname.color          = text_color_normal;
  601.  
  602.     s_playermodel.player.generic.type      = MTYPE_BITMAP;
  603.     s_playermodel.player.generic.flags     = QMF_INACTIVE;
  604.     s_playermodel.player.generic.ownerdraw = PlayerModel_DrawPlayer;
  605.     s_playermodel.player.generic.x           = 400;
  606.     s_playermodel.player.generic.y           = -40;
  607.     s_playermodel.player.width               = 32*10;
  608.     s_playermodel.player.height            = 56*10;
  609.  
  610.     s_playermodel.arrows.generic.type        = MTYPE_BITMAP;
  611.     s_playermodel.arrows.generic.name        = MODEL_ARROWS;
  612.     s_playermodel.arrows.generic.flags        = QMF_INACTIVE;
  613.     s_playermodel.arrows.generic.x            = 125;
  614.     s_playermodel.arrows.generic.y            = 340;
  615.     s_playermodel.arrows.width                = 128;
  616.     s_playermodel.arrows.height                = 32;
  617.  
  618.     s_playermodel.left.generic.type            = MTYPE_BITMAP;
  619.     s_playermodel.left.generic.flags        = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
  620.     s_playermodel.left.generic.callback        = PlayerModel_MenuEvent;
  621.     s_playermodel.left.generic.id            = ID_PREVPAGE;
  622.     s_playermodel.left.generic.x            = 125;
  623.     s_playermodel.left.generic.y            = 340;
  624.     s_playermodel.left.width                  = 64;
  625.     s_playermodel.left.height                  = 32;
  626.     s_playermodel.left.focuspic                = MODEL_ARROWSL;
  627.  
  628.     s_playermodel.right.generic.type        = MTYPE_BITMAP;
  629.     s_playermodel.right.generic.flags        = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
  630.     s_playermodel.right.generic.callback    = PlayerModel_MenuEvent;
  631.     s_playermodel.right.generic.id            = ID_NEXTPAGE;
  632.     s_playermodel.right.generic.x            = 125+61;
  633.     s_playermodel.right.generic.y            = 340;
  634.     s_playermodel.right.width                  = 64;
  635.     s_playermodel.right.height              = 32;
  636.     s_playermodel.right.focuspic            = MODEL_ARROWSR;
  637.  
  638.     s_playermodel.back.generic.type        = MTYPE_BITMAP;
  639.     s_playermodel.back.generic.name     = MODEL_BACK0;
  640.     s_playermodel.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
  641.     s_playermodel.back.generic.callback = PlayerModel_MenuEvent;
  642.     s_playermodel.back.generic.id        = ID_BACK;
  643.     s_playermodel.back.generic.x        = 0;
  644.     s_playermodel.back.generic.y        = 480-64;
  645.     s_playermodel.back.width              = 128;
  646.     s_playermodel.back.height              = 64;
  647.     s_playermodel.back.focuspic         = MODEL_BACK1;
  648.  
  649.     Menu_AddItem( &s_playermodel.menu,    &s_playermodel.banner );
  650.     Menu_AddItem( &s_playermodel.menu,    &s_playermodel.framel );
  651.     Menu_AddItem( &s_playermodel.menu,    &s_playermodel.framer );
  652.     Menu_AddItem( &s_playermodel.menu,    &s_playermodel.ports );
  653.     Menu_AddItem( &s_playermodel.menu,    &s_playermodel.playername );
  654.     Menu_AddItem( &s_playermodel.menu,    &s_playermodel.modelname );
  655.     Menu_AddItem( &s_playermodel.menu,    &s_playermodel.skinname );
  656.  
  657.     for (i=0; i<MAX_MODELSPERPAGE; i++)
  658.     {
  659.         Menu_AddItem( &s_playermodel.menu,    &s_playermodel.pics[i] );
  660.         Menu_AddItem( &s_playermodel.menu,    &s_playermodel.picbuttons[i] );
  661.     }
  662.  
  663.     Menu_AddItem( &s_playermodel.menu,    &s_playermodel.player );
  664.     Menu_AddItem( &s_playermodel.menu,    &s_playermodel.arrows );
  665.     Menu_AddItem( &s_playermodel.menu,    &s_playermodel.left );
  666.     Menu_AddItem( &s_playermodel.menu,    &s_playermodel.right );
  667.     Menu_AddItem( &s_playermodel.menu,    &s_playermodel.back );
  668.  
  669.     // find all available models
  670. //    PlayerModel_BuildList();
  671.  
  672.     // set initial states
  673.     PlayerModel_SetMenuItems();
  674.  
  675.     // update user interface
  676.     PlayerModel_UpdateGrid();
  677.     PlayerModel_UpdateModel();
  678. }
  679.  
  680. /*
  681. =================
  682. PlayerModel_Cache
  683. =================
  684. */
  685. void PlayerModel_Cache( void )
  686. {
  687.     int    i;
  688.  
  689.     for( i = 0; playermodel_artlist[i]; i++ ) {
  690.         trap_R_RegisterShaderNoMip( playermodel_artlist[i] );
  691.     }
  692.  
  693.     PlayerModel_BuildList();
  694.     for( i = 0; i < s_playermodel.nummodels; i++ ) {
  695.         trap_R_RegisterShaderNoMip( s_playermodel.modelnames[i] );
  696.     }
  697. }
  698.  
  699. void UI_PlayerModelMenu(void)
  700. {
  701.     PlayerModel_MenuInit();
  702.  
  703.     UI_PushMenu( &s_playermodel.menu );
  704.  
  705.     Menu_SetCursorToItem( &s_playermodel.menu, &s_playermodel.pics[s_playermodel.selectedmodel % MAX_MODELSPERPAGE] );
  706. }
  707.  
  708.  
  709.